// CLASS hardwareIO:
// This class takes care of the INPUT OUTPUT LOW LEVEL ROUTINES:
// (1) ADC (readout lock in amp output)
// (2) DAC (control mirrors and red laser)
// (3) control green laser
// (4) Set Prescalers (for lock in reference generation)

#ifndef hardwareIO_h
#define hardwareIO_h

#include "WProgram.h"
#include "SpiMCP4922.h"

//**** LOCKIN amplifier:
#define LOCKIN_PIN 0 
#define EIGHT_BITS 0 // redaout mode: this will use SPI based ADC (external chip) 
#define TEN_BITS 1   // redout mode: this will use the standard analogRead() method
#define I_Volts_SAT 5 // this is 5V (the saturation voltage for the APD+LockIn+ADC, being it the arduino (when in normal mode) or the SPI. This saturation voltage could be different for each mode!?

//**** RED laser (rem: the red laser power will be controlled in mW)
#define redLaserPin 2 // use SPI DAC
#define MAX_AD_RED 4095 // 10 bits SPI interface (output: 0-5 volts)
#define MAX_RedLaserPower 3 // in mW  - measuring the power RIGHT AFTER THE MIRRORS
#define MIN_RedLaserPower 0 // in mW
#define Volts_to_AD_RED 819 //=(MAX_AD_RED/5.0) 
#define mW_to_Volts_RED 1.667 //(5.0/(MAX_RedLaserPower-MIN_RedLaserPower)) //  we assume linear relation from volts to mW
#define mW_to_AD_RED 1365 // (mW_to_Volts_RED*Volts_to_AD_RED)

//**** GREEN laser: 
#define greenLaserPin 48 // just use digital IO (HIGH/LOW)
// Nothing to do (HIGH or LOW for the time being...)

//**** MIRRORS: 
//The DAC is 12 bytes capable (Max=4096), but we will limit this a little. 
#define MAX_AD_MIRRORS 4000 // Absolute maximum for the SPI voltage (5V). This is for checking hardware compliance, but max and min angles can be defined for X and Y in each LivingSpot instance.
#define MIN_AD_MIRRORS 0
// We assume that the center of the mirror is at MAX_AD_MIRRORS/2 = 2000:
#define CENTER_AD_MIRROR_X 2000 // This MUST BE the direction of the photodetector. 
#define CENTER_AD_MIRROR_Y 2000 // This MUST BE the direction of the photodetector.
#define MAX_DEG_MIRROR_X 20 // Angular value when AD mirror value is MAX_AD_MIRRORS (same for X and Y). ATTN! this value must be calibrated! otherwise cartesian coordinates will be wrong...
#define MIN_DEG_MIRROR_X -20 // Angular value when AD mirror value is 0
#define MAX_DEG_MIRROR_Y 20
#define MIN_DEG_MIRROR_Y -20
// REM: we have for instance, if Az is in degrees and assuming a linear relationship between voltage and degrees: 
// AD value for X mirror =  (Az-MIN_DEG_MIRROR_X)/(MAX_DEG_MIRROR_X-MIN_DEG_MIRROR_X)*MAX_AD_MIRRORS
//float deg_to_AD_MIRROR_X=1.0*(MAX_DEG_MIRROR_X-MIN_DEG_MIRROR_X)/(MAX_AD_MIRRORS-MIN_AD_MIRRORS);
//float deg_to_AD_MIRROR_Y=1.0*(MAX_DEG_MIRROR_Y-MIN_DEG_MIRROR_Y)/(MAX_AD_MIRRORS-MIN_AD_MIRRORS);
//float AD_to_Deg_MIRROR_X=1.0*(MAX_AD_MIRRORS-MIN_AD_MIRRORS)/(MAX_DEG_MIRROR_X-MIN_DEG_MIRROR_X);
//float AD_to_Deg_MIRROR_Y=1.0*(MAX_AD_MIRRORS-MIN_AD_MIRRORS)/(MAX_DEG_MIRROR_Y-MIN_DEG_MIRROR_Y);
//float deg_to_AD_MIRROR=1.0/AD_to_Deg_MIRROR_X;// this will be used for radius update

//**** BUTTONS: 
// NOTE: we will use interrupt 0, activated by rising edge on INTERRUPT_BUTTON_PIN (2), and then we will read all the bits of the
// eight buttons (actually, we use only 6 for the time being). 
#define INTERRUPT_READ_BUTTONS 0 //THIS IS PIN 2 !!! 
#define interruptButtonPin 2
#define BUTTON_BYTE_PORT PINA

// **** POTENTIOMETERS: 
#define potA_pin 8 // analog inputs
#define potB_pin 9
//float valuePotA, valuePotB; //Will be normalized.
// Note: the value of the potentiometers is scanned when we press a particular BUTTON 

// **** BUZZER (PWM): 
#define buzzer_pin 6 // (PWM output)

// **** REFERENCE SIGNAL: 
#define testPin_OC1A 11 // this is, output compare pin OC1A //connected to CK2 = lockIn clock
#define testPin_OC1B 12 // this is, output compare pin OC1B //connected to CK1 = laser clock
#define testPin_OC1C 13

// ==================================================================================================================================================================

class HardwareIO {
public:
	void init(void);

	int analogReadMode; //  analog read mode (could be private). Can be 8_BITS, 10_BITS 
	void setAnalogReadMode(int);
	float LockInRead_Volts(); 
	int LockInRead_AD(); 
        float LockInAD_to_Volts(int); 

	// buttons readout function (interrupt based): 
	void readButtons();
	byte buttonByte;
	boolean processButton; // will set to true when a button is pressed (it must be set to 0 after processing button input, probably in the main program)

	// potentiometer values (normalized)
	float valuePotA, valuePotB; 
	float readPotA(); 
	float readPotB(); 

	// SPI control for DAC for mirrors and red laser power: 
	SPI Spi; // note: this could be private, but we may want to access SPI class methods directly.

	// mirror degree-to-AD units conversion factors: 
	float AD_to_Deg_MIRROR_X;//=1.0*(MAX_DEG_MIRROR_X-MIN_DEG_MIRROR_X)/(MAX_AD_MIRRORS-MIN_AD_MIRRORS);
	float AD_to_Deg_MIRROR_Y;//=1.0*(MAX_DEG_MIRROR_Y-MIN_DEG_MIRROR_Y)/(MAX_AD_MIRRORS-MIN_AD_MIRRORS);

	// Mirror position:
	void setMirrorX_Deg(float _Az); 
	void setMirrorY_Deg(float _El);
	void setMirrorX_AD(int _AzAD); 
	void setMirrorY_AD(int _ElAD);
	void setMirrorsXY_AD(int _xAD, int _yAD); 
	void setMirrorsCenter();
	void getAnglesFromAD(float &Az, float &El, int _xAD, int _yAD); 
	//void setZoneDelimiters(...) // this could be here, instead on the LivingSpot class

	// Red laser:
	void setRedPower_AD(int powerAD);// from 0 to MAX_RED_POWER
	void setRedPower_mW(float powermW); 
        
	// Green laser: 
	void setGreenPower(boolean); // HIGH or LOW

	// init PWM for reference generation:
	void initPWM();

	// reference signal: 
	void setRefFreq(int);
	void incRefFreq(int inc=1);
	void decRefFreq(int dec=1);

	// buzzer: 
	void setBuzzerFreq(int); 
	void setBuzzer(boolean state);
	void buzzerBip(int timebip=300, int times=1);

	// LCD output (could make a class, but c'mon): 
	void clearLCD();
	void clearLine(int line);
	void displayLineLCD(char *string, int line);
	void displayLineLCD(float num, int line); // we can also use with integer, by forcing the type: (float)number
	void displayLineLCD(byte num, int line); 

	float refFreq; // could be private

private:
	byte FastAnalogRead(int pin);
	byte FastAnalogReadPin0();

};

extern HardwareIO IO;

#endif

